<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8">
  <title>虚拟DOM</title>
  <script src="script/react.development.js"></script>
  <script src="script/react-dom.development.js"></script>
  <script src="script/babel.min.js"></script>
</head>

<body>
  <button id="btn">点我一下</button>
  <hr>
  <div id="root"></div>

  <script type="text/babel">

    //创建一个数据
    const data = ['孙悟空', '猪八戒', '沙和尚'];

    // 创建列表
    const list = <ul>
      {/*data.map(item => <li key={item}>{item}</li>)*/}
      {data.map((item, index) => <li key={index}>{item}</li>)}
    </ul>;

    // 获取根元素
    const root = ReactDOM.createRoot(document.getElementById('root'));
    // 渲染元素
    root.render(list);

    /*
    *   在React我们操作的元素被称为React元素，并不是真正的原生DOM元素，
    *       React通过虚拟DOM 将React元素 和 原生DOM，进行映射，虽然操作的React元素，但是这些操作最终都会在真实DOM中体现出来
    *       虚拟DOM的好处：
    *           1.降低API复杂度
    *           2.解决兼容问题
    *           3.提升性能（减少DOM的不必要操作）
    *
    *   每当我们调用root.render()时，页面就会发生重新渲染
    *       React会通过diffing算法，将新的元素和旧的元素进行比较
    *       通过比较找到发生变化的元素，并且只对变化的元素进行修改，没有发生的变化不予处理
    * */
    document.getElementById('btn').onclick = function () {
      // 重新渲染页面
      //创建一个数据
      const data = ['唐僧', '孙悟空', '猪八戒', '沙和尚'];
      // 创建列表
      const list = <ul>
        {data.map(item => <li key={item}>{item}</li>)}
        {/* data.map((item, index) => <li key={index}>{item}</li>) */}
      </ul>;
      // 渲染元素
      root.render(list);

      /*
      *   旧数据
      *       ul
      *           li>孙悟空
      *           li>猪八戒
      *           li>沙和尚
      *  新数据
      *       ul
      *           li>孙悟空
      *           li>猪八戒
      *           li>沙和尚
      *   比较两次数据时，React会先比较父元素，父元素如果不同，直接所有元素全部替换
      *       父元素一致，在去逐个比较子元素，直到找到所有发生变化的元素为止
      *   上例中，新旧两组数据完全一致，所以没有任何DOM对象被修改
      *
      *
      * 旧数据
      *       ul
      *           li>孙悟空
      *           li>猪八戒
      *           li>沙和尚
      *  新数据
      *       ul
      *           li>tom
      *           li>猪八戒
      *           li>沙和尚
      *
      *  上例中，只有第一个li发生变化，所以只有第一个li被修改，其他元素不变
      *
      *  当我们在JSX中显示数组中，数组中每一个元素都需要设置一个唯一key，否则控制台会显示红色警告
      *       重新渲染页面时，React会按照顺序依次比较对应的元素，当渲染一个列表时如果不指定key，同样也会按照顺序进行比较，
      *       如果列表的顺序永远不会发生变化，这么做当然没有问题，但是如果列表的顺序会发生变化，这可能会导致性能问题出现
      *
      *
      *   旧数据
      *       ul
      *           li>孙悟空
      *           li>猪八戒
      *           li>沙和尚
      *   新数据
      *       ul
      *           li>孙悟空
      *           li>猪八戒
      *           li>沙和尚
      *           li>唐僧
      *
      *   上例中，在列表的最后添加了一个新元素，并没有改变其他的元素的顺序，所以这种操作不会带来性能问题
      *
      *
      *
      *   旧数据
      *       ul
      *           li>孙悟空
      *           li>猪八戒
      *           li>沙和尚
      *   新数据
      *       ul
      *           li>唐僧
      *           li>孙悟空
      *           li>猪八戒
      *           li>沙和尚
      *
      *   上例中，在列表的最前边插入了一个新元素，其他元素内容并没有发生变化，
      *       但是由于新元素插入到了开始位置，其余元素的位置全都发生变化，而React默认是根据位置比较元素
      *       所以 此时，所有元素都会被修改
      *
      *   为了解决这个问题，React为列表设计了一个key属性，
      *       key的作用相当于ID，只是无法在页面中查看，当设置key以后，再比较元素时，
      *       就会比较相同key的元素，而不是按照顺序进行比较
      *   在渲染一个列表时，通常会给列表项设置一个唯一的key来避免上述问题
      *       （这个key在当前列表中唯一即可）
      *       注意：
      *           1.开发中一般会采用数据的id作为key
      *           2.尽量不要使用元素的index作为key
      *               索引会跟着元素顺序的改变而改变，所以使用索引做key跟没有key是一样的
      *                   唯一的不同就是，控制台的警告没了
      *               当元素的顺序不会发生变化时，用索引做key也没有什么问题
      *   旧数据
      *       ul
      *           li(key=孙悟空)>孙悟空
      *           li(key=猪八戒)>猪八戒
      *           li(key=沙和尚)>沙和尚
      *   新数据
      *       ul
      *           li(key=唐僧)>唐僧
      *           li(key=孙悟空)>孙悟空
      *           li(key=猪八戒)>猪八戒
      *           li(key=沙和尚)>沙和尚
      * */
    };



  </script>
</body>

</html>